#include <afxwin.h>
#include <AppModel/Include/Task.h>

unsigned int Task::task_cycle(void* instancia)
{
	Task* task = (Task*)instancia;
	while (1)
	{
		task->cycle_function(task->owner);

		task->sleep();
		
		if (task->end_thread)
		{
            if (NULL != task->finalization_semaphore)
            {
                task->finalization_semaphore->signal();
            }
			delete task;
			return 0;
		}
	}
}

Task::Task(TaskCallbackFunction f, void* own, T_TaskPriority _priority, int _sleep_time, Semaphore* finalization_semaphore)
{
	this->cycle_function = f;
	this->owner = own;
	this->end_thread = false;
	this->is_running = false;
	this->priority = _priority;

	this->sleep_time = _sleep_time;
	this->evento_sinc = CreateEvent(NULL, false, false, NULL);
	this->evento_fin = CreateEvent(NULL, false, false, NULL);

    this->finalization_semaphore = finalization_semaphore;
}

void Task::indicateTaskCallbackFunction(TaskCallbackFunction f, void * _owner)
{
	cycle_function = f;
	owner = _owner; 
}

Task::~Task()
{
	CloseHandle(evento_sinc);
	CloseHandle(evento_fin);
}

void Task::stop()
{
	end_thread=true;
	is_running = false;	
}

void Task::start()
{
	init_thread();
	is_running = true;
}

bool Task::isRunning()
{
	return is_running;
}

void Task::sleep()
{
	if(sleep_time != TASK_SLEEP_TIME_NULL)
		WaitForSingleObject(evento_sinc, sleep_time);
}

void Task::notify_end()
{
	SetEvent(evento_fin);
}


void Task::init_thread()
{
int win_priority = 0;
	switch(priority)
	{
	case T_TaskPriority::TASK_PRIORITY_CRITICAL:
		win_priority = THREAD_PRIORITY_TIME_CRITICAL;
		break;
	case T_TaskPriority::TASK_PRIORITY_HIGH:
		win_priority = THREAD_PRIORITY_HIGHEST;
		break;
	case T_TaskPriority::TASK_PRIORITY_ABOVE_NORMAL:
		win_priority = THREAD_PRIORITY_ABOVE_NORMAL;
		break;
	case T_TaskPriority::TASK_PRIORITY_NORMAL:
		win_priority = THREAD_PRIORITY_NORMAL;
		break;
	case T_TaskPriority::TASK_PRIORITY_BELOW_NORMAL:
		win_priority = THREAD_PRIORITY_BELOW_NORMAL;
		break;
	case T_TaskPriority::TASK_PRIORITY_LOW:
		win_priority = THREAD_PRIORITY_LOWEST;
		break;
	case T_TaskPriority::TASK_PRIORITY_IDLE:
		win_priority = THREAD_PRIORITY_IDLE;
		break;
	}

	SECURITY_ATTRIBUTES security_att;
	security_att.nLength = sizeof(SECURITY_ATTRIBUTES);
	security_att.lpSecurityDescriptor = NULL;
	security_att.bInheritHandle = TRUE; //puede ser usado por procesos hijos el handle
	AfxBeginThread(Task::task_cycle, this,win_priority,0,0,&security_att);}

void Task::wait_for_real_end()
{
	SetEvent(evento_sinc);
	WaitForSingleObject(evento_fin, INFINITE);
}
